#pragma once
#include <jsoncpp/json/json.h>
#include "abstract.hpp"
#include "field.hpp"
#include "tool.hpp"

namespace RPC
{
    // 提高代码复用，后续继承message的类都不用自己单独实现
    class JsonMessage : public BaseMessage
    {
    public:
        using Ptr = std::shared_ptr<JsonMessage>;

        virtual std::string serialize() override
        {
            std::string body;
            bool ret = JSON::serialize(_body, body);
            if (ret == false)
            {
                return "";
            }
            return body;
        }

        virtual bool desrialize(const std::string &msg) override
        {
            JSON::deserialize(msg, _body);
            std::cout << _body.toStyledString();
            return true;
        }

    protected:
        Json::Value _body;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using Ptr = std::shared_ptr<JsonRequest>;
    };

    class JsonResponse : public JsonMessage
    {
    public:
        using Ptr = std::shared_ptr<JsonResponse>;
        // 在响应中，大部分响应中，只有响应状态码，因此只需要判断响应状态码是否存在，类型是否正确
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true)
            {
                ERROR_LOG("响应中没有响应状态码！");
                return false;
            }
            if (_body[KEY_RCODE].isIntegral() == false)
            {
                ERROR_LOG("响应状态码类型错误！");
                return false;
            }
            return true;
        }

        virtual RCode rCode()
        {
            return (RCode)_body[KEY_RCODE].asInt();
        }

        virtual void setRCode(RCode rcode)
        {
            _body[KEY_RCODE] = (int)rcode;
        }
    };

    class RpcRequest : public JsonRequest
    {
    public:
        using Ptr = std::shared_ptr<RpcRequest>;
        bool check() override
        {
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false)
            {
                return false;
            }
            if (_body[KEY_PARAMETER].isNull() == true ||
                _body[KEY_PARAMETER].isObject() == false)
            {
                return false;
            }
            return true;
        }

        void setMethod(const std::string &method_name)
        {
            _body[KEY_METHOD] = method_name;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setParam(const Json::Value &val)
        {
            _body[KEY_PARAMETER] = val;
        }

        Json::Value Param()
        {
            return _body[KEY_PARAMETER];
        }
    };

    class TopicRequest : public JsonRequest
    {
    public:
        using Ptr = std::shared_ptr<TopicRequest>;
        bool check()
        {
            if (_body[KEY_TOPIC_KEY].isNull() == true ||
                _body[KEY_TOPIC_KEY].isString() == false)
            {
                ERROR_LOG("主题中没有主题名称或者主题错误！");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_OPTYPE].isIntegral() == false)
            {
                ERROR_LOG("主题类型为空，或者主题错误！");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)TopicOpType::TOPIC_PUBLISH &&
                    _body[KEY_TOPIC_MSG].isNull() == true ||
                _body[KEY_TOPIC_MSG].isString() == false)
            {
                ERROR_LOG("主题消息发送请求中没有消息发布字段或者字段错误！");
                return false;
            }

            return true;
        }

        void setTopicKey(const std::string &topic)
        {
            _body[KEY_TOPIC_KEY] = topic;
        }

        std::string topicKey()
        {
            return _body[KEY_TOPIC_KEY].asString();
        }

        void setOpType(TopicOpType type)
        {
            _body[KEY_OPTYPE] = (int)type;
        }

        TopicOpType opType()
        {
            return (TopicOpType)_body[KEY_OPTYPE].asInt();
        }

        void setMessage(const std::string &msg)
        {
            _body[KEY_TOPIC_MSG] = msg;
        }

        std::string message()
        {
            return _body[KEY_TOPIC_MSG].asString();
        }
    };

    using Address = std::pair<std::string, int>;
    class ServiceRequest : public JsonRequest
    {
    public:
        using Ptr = std::shared_ptr<ServiceRequest>;

        bool check()
        {
            if (_body[KEY_METHOD].isNull() == true ||
                _body[KEY_METHOD].isString() == false)
            {
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true ||
                _body[KEY_METHOD].isIntegral() == false)
            {
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() != (int)ServiceOpType::SERVICE_DISCOVERY &&
                    _body[KEY_HOST].isNull() == true ||
                _body[KEY_HOST].isObject() == false ||
                _body[KEY_HOST][KEY_HOST_PORT].isNull() == true ||
                _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false ||
                _body[KEY_HOST][KEY_HOST_IP].isNull() == true ||
                _body[KEY_HOST][KEY_HOST_IP].isString() == false)
            {
                return false;
            }
            return true;
        }

        void setMethod(const std::string &method) // 要注册的服务方法
        {
            _body[KEY_METHOD] = method;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setOpType(ServiceOpType type)
        {
            _body[KEY_OPTYPE] = (int)type;
        }

        ServiceOpType opType()
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        void setHost(const Address &host)
        {
            Json::Value val;
            val[KEY_HOST_IP] = host.first;
            val[KEY_HOST_PORT] = host.second;
            _body[KEY_HOST] = val;
        }

        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }
    };

    class RpcResponse : public JsonResponse
    {
    public:
        using Ptr = std::shared_ptr<RpcResponse>;

        Json::Value Result()
        {
            return _body[KEY_RESULT];
        }

        void setResult(const Json::Value &val)
        {
            _body[KEY_RESULT] = val;
        }
    };

    class TopicResponse : public JsonResponse
    {
    public:
        using Ptr = std::shared_ptr<TopicResponse>;
    };

    class ServiceResponse : public JsonResponse
    {
    public:
        using Ptr = std::shared_ptr<ServiceResponse>;

        void setOpType(const ServiceOpType &type)
        {
            _body[KEY_OPTYPE] = (int)type;
        }

        ServiceOpType Optype()
        {
            return (ServiceOpType)_body[KEY_OPTYPE].asInt();
        }

        void setMethod(const std::string &method)
        {
            _body[KEY_METHOD] = method;
        }

        std::string Method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setHost(const std::vector<Address> &addrarr)
        {
            for (auto &x : addrarr)
            {
                Json::Value val;
                val[KEY_HOST_IP] = x.first;
                val[KEY_HOST_PORT] = x.second;
                _body[KEY_HOST].append(val);
            }
        }

        std::vector<Address> host()
        {
            std::vector<Address> addr;
            int sz = _body[KEY_HOST].size();
            for (int i = 0; i < sz; i++)
            {
                Address temp;
                temp.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                temp.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addr.push_back(temp);
            }
            return addr;
        }
    };

    class MessageFactory
    {
    public:
        static BaseMessage::Ptr create(MType type)
        {
            switch (type)
            {
            case MType::REQ_RPC:
                return std::make_shared<RpcRequest>();
            case MType::RES_RPC:
                return std::make_shared<RpcResponse>();
            case MType::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MType::RES_TOPIC:
                return std::make_shared<TopicResponse>();
            case MType::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MType::RES_SERVICE:
                return std::make_shared<ServiceResponse>();
            }
            return BaseMessage::Ptr();
        }
        template <typename T, typename... Args>
        static std::shared_ptr<T> create(Args &&...args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };
}